package org.holynite.poi.dsl.word

import org.apache.poi.wp.usermodel.HeaderFooterType
import org.apache.poi.xwpf.usermodel.*
import org.holynite.poi.dsl.units.CellCorrdinate
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth
import java.io.FileInputStream
import java.nio.file.Files
import java.nio.file.Paths
import javax.imageio.ImageIO

fun document(document: XWPFDocument.() -> Unit) = XWPFDocument().apply(document)

fun XWPFDocument.paragraph(paragraph: XWPFParagraph.() -> Unit) = createParagraph().apply(paragraph)

fun XWPFDocument.margin(top: Int, right: Int, bottom: Int, left: Int) {
    val pageMargin = document.body.addNewSectPr().addNewPgMar()
    pageMargin.left = left.toBigInteger()
    pageMargin.right = right.toBigInteger()
    pageMargin.top = top.toBigInteger()
    pageMargin.bottom = bottom.toBigInteger()
}

fun XWPFDocument.header(header: XWPFHeader.() -> Unit) = createHeader(HeaderFooterType.DEFAULT).apply(header)

fun XWPFDocument.evenHeader(header: XWPFHeader.() -> Unit) = createHeader(HeaderFooterType.EVEN).apply(header)

fun XWPFDocument.footer(footer: XWPFFooter.() -> Unit) = createFooter(HeaderFooterType.DEFAULT).apply(footer)

fun XWPFDocument.evenFooter(footer: XWPFFooter.() -> Unit) = createFooter(HeaderFooterType.EVEN).apply(footer)

fun XWPFDocument.picture(path: String, format: Int, picture: XWPFPictureData.() -> Unit) {
    if (Files.exists(Paths.get(path))) {
        val picId = addPictureData(FileInputStream(path), format)
        getPictureDataByID(picId).apply(picture)
    }
}

fun XWPFParagraph.run(text: String = "", run: XWPFRun.() -> Unit) {
    with(createRun()) {
        setText(text)
        apply(run)
    }
}

fun XWPFParagraph.firstLineIndent(size: Int) {
    indentationFirstLine = size
}

fun XWPFParagraph.hangingIndent(size: Int) {
    indentationHanging = size
}

fun XWPFRun.font(
        family: String,
        size: Int,
        bold: Boolean = false,
        italic: Boolean = false,
        strike: Boolean = false,
        underline: UnderlinePatterns = UnderlinePatterns.NONE,
        doubleStrike: Boolean = false
) {
    fontFamily = family
    fontSize = size
    isBold = bold
    isItalic = italic
    isStrikeThrough = strike
    setUnderline(underline)
    setDoubleStrikethrough(doubleStrike)
}

fun XWPFRun.picture(path: String, maxWidth: Int = 0, maxHeight: Int = 0, picture: XWPFPicture.() -> Unit) {
    if (!Files.exists(Paths.get(path))) return
    val readers = ImageIO.getImageReaders(FileInputStream(path))
    if (!readers.hasNext()) return
    val reader = readers.next()
    val format = when (reader.formatName.toLowerCase()) {
        "jpeg" -> Document.PICTURE_TYPE_JPEG
        "png" -> Document.PICTURE_TYPE_PNG
        "gif" -> Document.PICTURE_TYPE_GIF
        "bitmap" -> Document.PICTURE_TYPE_BMP
        else -> Document.PICTURE_TYPE_BMP
    }
    val image = ImageIO.read(FileInputStream(path))
    var imageWidth = if (image.width > maxWidth && maxWidth != 0) maxWidth else image.width
    var imageHeight = if (image.height > maxHeight && maxHeight != 0) maxHeight else image.height
    if (imageWidth >= imageHeight) {
        imageHeight = imageWidth * image.height / image.width
    } else {
        imageWidth = imageHeight * imageWidth / image.height
    }
    addPicture(FileInputStream(path), format, Paths.get(path).fileName.toString(), imageWidth, imageHeight).apply(picture)
}

fun XWPFDocument.table(table: XWPFTable.() -> Unit) = createTable().apply(table)

fun XWPFTable.column(cols: Int) = repeat(cols) { this.addNewCol() }

fun XWPFTable.row(row: XWPFTableRow.() -> Unit) = createRow().apply(row)

fun XWPFTable.autoStretch() {
    ctTbl.tblPr.tblW.type = STTblWidth.AUTO
}

fun XWPFTable.width(width: Int) {
    ctTbl.tblPr.tblW.type = STTblWidth.DXA
    ctTbl.tblPr.tblW.w = width.toBigInteger()
}

fun XWPFTable.margin(top: Int, right: Int, bottom: Int, left: Int) = setCellMargins(top, left, bottom, right)

fun XWPFTable.margin(horizontal: Int, vertical: Int) = setCellMargins(vertical, horizontal, vertical, horizontal)

fun XWPFTable.margin(margin: Int) = setCellMargins(margin, margin, margin, margin)

fun XWPFTable.merge(from: CellCorrdinate, to: CellCorrdinate) {

}

fun XWPFTableRow.cell(pos: Int, cell: XWPFTableCell.() -> Unit) = getCell(pos).apply(cell)

fun XWPFTableRow.cell(cell: XWPFTableCell.() -> Unit) = createCell().apply(cell)

fun XWPFTableRow.repeat() {
    isRepeatHeader = true
}

fun XWPFTableRow.merge(range: IntRange) {

}

fun XWPFTableCell.paragrpah(pos: Int, paragraph: XWPFParagraph.() -> Unit) = paragraphs[pos].apply(paragraph)

fun XWPFTableCell.paragraph(paragraph: XWPFParagraph.() -> Unit) = addParagraph().apply(paragraph)

fun XWPFTableCell.autoStretch() {
    ctTc.addNewTcPr().addNewTcW().type = STTblWidth.AUTO
}